package com.lcy.service.impl;


import cn.hutool.core.collection.CollUtil;
import com.google.common.collect.Sets;
import com.mybatisflex.core.query.QueryChain;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.core.util.StringUtil;
import com.mybatisflex.spring.service.impl.ServiceImpl;
import com.lcy.exception.BusinessException;
import com.lcy.mapper.OjPostCommentMapper;
import com.lcy.mapper.OjPostMapper;
import com.lcy.mapstruct.OjPostCommentConverter;
import com.lcy.model.dto.postComment.PostCommentRequest;
import com.lcy.model.entity.OjPostComment;
import com.lcy.model.vo.PostCommentVo;
import com.lcy.security.utils.SecurityHelper;
import com.lcy.service.OjPostCommentService;
import com.lcy.sys.mapper.SysUserMapper;
import com.lcy.sys.model.entity.SysUser;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

import static com.lcy.model.entity.table.OjPostCommentTableDef.OJ_POST_COMMENT;
import static com.lcy.model.entity.table.OjPostTableDef.OJ_POST;
import static com.lcy.sys.model.entity.table.SysUserTableDef.SYS_USER;

/**
 * 帖子评论 服务层实现。
 *
 * @author zhang.rx
 * @since 2024/5/20
 */
@Slf4j
@Service
public class OjPostCommentServiceImpl extends ServiceImpl<OjPostCommentMapper, OjPostComment> implements OjPostCommentService {

    @Resource
    private OjPostCommentConverter converter;

    @Resource
    private OjPostCommentMapper commentMapper;

    @Resource
    private OjPostMapper postMapper;

    @Resource
    private SysUserMapper userMapper;

    @Override
    public Boolean save(PostCommentRequest req) {
        // 获取当前用户
        SysUser user = SecurityHelper.getUser();
        if (user == null || user.getId() == null) {
            log.error("评论失败：用户未登录或用户ID为空");
            throw new BusinessException("请先登录");
        }
        
        log.info("保存评论请求: postId={}, parentId={}, content={}, 用户ID={}", 
                req.getPostId(), req.getParentId(), 
                req.getContent() != null ? req.getContent().substring(0, Math.min(20, req.getContent().length())) + "..." : "null", 
                user.getId());
        
        // 验证帖子是否存在
        if (req.getPostId() == null) {
            log.error("评论失败：帖子ID为空");
            throw new BusinessException("帖子ID不能为空");
        }
        
        long count = postMapper
                .selectCountByCondition(OJ_POST.ID.eq(req.getPostId()));
        if (count == 0) {
            log.error("评论失败：帖子不存在，postId={}", req.getPostId());
            throw new BusinessException("帖子不存在");
        }
        
        // 验证父评论是否存在（如果有）
        if (req.getParentId() != null) {
            long parentExists = commentMapper.selectCountByCondition(OJ_POST_COMMENT.ID.eq(req.getParentId()));
            if (parentExists == 0) {
                log.error("评论失败：父评论不存在，parentId={}", req.getParentId());
                throw new BusinessException("回复的评论不存在");
            }
        }
        
        // 转换并保存评论
        OjPostComment entity = converter.toEntity(req);
        entity.setAuthorId(user.getId());
        
        // 确保没有设置ID，让数据库生成
        entity.setId(null);
        
        boolean result = save(entity);
        log.info("评论保存结果: {}, 生成的评论ID: {}", result, entity.getId());
        return result;
    }

    @Override
    public List<PostCommentVo> listChildren(String parentId) {
        if (StringUtil.isBlank(parentId)) {
            log.error("获取子评论失败：父评论ID为空");
            return new ArrayList<>();
        }
        
        log.info("获取子评论列表: parentId={}", parentId);
        
        try {
            Long parentIdLong = Long.parseLong(parentId);
            QueryWrapper queryWrapper = new QueryWrapper().where(OJ_POST_COMMENT.PARENT_ID.eq(parentIdLong));
        List<OjPostComment> postComments = commentMapper.selectListByQuery(queryWrapper);
            
            log.info("查询到子评论数量: {}", postComments.size());
            
            if (CollUtil.isEmpty(postComments)) {
                return new ArrayList<>();
            }
            
            // 处理BLOB/CLOB内容
            postComments.forEach(this::processBlobContent);
            
        Set<Long> userIds = postComments.stream().map(OjPostComment::getAuthorId).collect(Collectors.toSet());
        List<PostCommentVo> voList = converter.toVoList(postComments);
        findUserInfo(voList, userIds);
        return voList;
        } catch (NumberFormatException e) {
            log.error("获取子评论失败：父评论ID格式错误, parentId={}", parentId, e);
            return new ArrayList<>();
        }
    }

    /**
     * 递归查询子节点
     */
    private void findChildren(PostCommentVo e, Set<Long> userIds) {
        findChildren(e, userIds, new HashSet<>());
    }
    
    /**
     * 递归查询子节点（带已处理ID集合）
     */
    private void findChildren(PostCommentVo e, Set<Long> userIds, Set<Long> processedIds) {
        // 防止重复处理同一个评论ID，避免循环依赖导致的堆栈溢出
        if (e.getId() == null || processedIds.contains(e.getId())) {
            return;
        }
        
        // 添加到已处理集合中
        processedIds.add(e.getId());
        
        if (e.getAuthorId() != null) {
        userIds.add(e.getAuthorId());
        }
        
        List<OjPostComment> list = QueryChain.of(commentMapper)
                .where(OJ_POST_COMMENT.PARENT_ID.eq(e.getId()))
                .list();
                
        if (CollUtil.isEmpty(list)) {
            return;
        }
        
        log.debug("查询到评论ID={}的子评论数量: {}", e.getId(), list.size());
        
        // 处理子评论中的BLOB/CLOB内容
        list.forEach(this::processBlobContent);
        
        e.setChildren(converter.toVoList(list));
        
        // 遍历子评论，同时传递已处理ID集合
        e.getChildren().forEach(child -> findChildren(child, userIds, processedIds));
    }


    @Override
    public List<PostCommentVo> list(String postId) {
        if (StringUtil.isBlank(postId)) {
            log.error("获取评论列表失败：帖子ID为空");
            return new ArrayList<>();
        }
        
        log.info("获取帖子评论列表: postId={}", postId);
        
        try {
            Long postIdLong = Long.parseLong(postId);
            
        QueryWrapper queryWrapper = new QueryWrapper()
                    .where(OJ_POST_COMMENT.POST_ID.eq(postIdLong))
                    .and(OJ_POST_COMMENT.PARENT_ID.isNull())
                    .orderBy(OJ_POST_COMMENT.CREATE_TIME.desc());
                    
        List<OjPostComment> postComments = commentMapper.selectListByQuery(queryWrapper);
            
            log.info("查询到根评论数量: {}", postComments.size());
            
            if (CollUtil.isEmpty(postComments)) {
                return new ArrayList<>();
            }
            
            // 打印原始数据，用于调试
            if (!postComments.isEmpty()) {
                OjPostComment firstComment = postComments.get(0);
                log.info("第一条原始评论数据: id={}, authorId={}, content类型={}, createTime={}", 
                         firstComment.getId(), firstComment.getAuthorId(), 
                         firstComment.getContent() != null ? firstComment.getContent().getClass().getName() : "null",
                         firstComment.getCreateTime());
            }
            
            // 处理BLOB内容
            postComments.forEach(this::processBlobContent);
            
        List<PostCommentVo> voList = converter.toVoList(postComments);
            
            // 检查转换后的数据
            if (!voList.isEmpty()) {
                PostCommentVo firstVo = voList.get(0);
                log.info("第一条转换后评论数据: id={}, authorId={}, content={}, createTime={}", 
                         firstVo.getId(), firstVo.getAuthorId(), 
                         firstVo.getContent() != null ? firstVo.getContent().substring(0, Math.min(20, firstVo.getContent().length())) + "..." : "null",
                         firstVo.getCreateTime());
            }
            
        Set<Long> userIds = Sets.newHashSet();
            
            // 从评论对象中收集用户ID
            voList.forEach(e -> {
                if (e.getAuthorId() != null) {
                    userIds.add(e.getAuthorId());
                } else {
                    log.warn("评论ID: {}的作者ID为null", e.getId());
                }
            });
            
            log.info("收集到的用户ID数量: {}", userIds.size());
            
            // 查询所有子节点，使用共享的已处理ID集合
            Set<Long> processedIds = new HashSet<>();
            voList.forEach(e -> findChildren(e, userIds, processedIds));
            
        findUserInfo(voList, userIds);
        return voList;
        } catch (NumberFormatException e) {
            log.error("获取评论列表失败：帖子ID格式错误, postId={}", postId, e);
            return new ArrayList<>();
        }
    }
    
    /**
     * 处理评论内容中的BLOB/CLOB数据
     * @param comment 评论实体
     */
    private void processBlobContent(OjPostComment comment) {
        if (comment == null) {
            return;
        }
        
        // 处理内容字段
        if (comment.getContent() != null) {
            Object content = comment.getContent();
            try {
                // 如果是字符串，直接使用
                if (content instanceof String) {
                    // 已经是字符串，不需要处理
                } else if (content instanceof java.sql.Clob) {
                    // 处理CLOB
                    java.sql.Clob clob = (java.sql.Clob) content;
                    StringBuilder sb = new StringBuilder();
                    try (java.io.BufferedReader reader = new java.io.BufferedReader(clob.getCharacterStream())) {
                        String line;
                        while ((line = reader.readLine()) != null) {
                            sb.append(line);
                        }
                        comment.setContent(sb.toString());
                    } catch (Exception e) {
                        log.error("处理CLOB内容失败", e);
                        comment.setContent("加载评论内容失败");
                    }
                } else if (content instanceof byte[]) {
                    // 处理BLOB
                    byte[] bytes = (byte[]) content;
                    comment.setContent(new String(bytes));
                } else {
                    // 其他类型，直接toString
                    comment.setContent(content.toString());
                }
            } catch (Exception e) {
                log.error("处理评论内容失败: {}", e.getMessage());
                comment.setContent("评论内容处理失败");
            }
        }
    }

    /**
     * 获取用户信息
     */
    private void findUserInfo(List<PostCommentVo> voList, Set<Long> userIds) {
        if (CollUtil.isEmpty(userIds)) {
            log.warn("没有需要查询的用户ID");
            return;
        }
        
        log.debug("查询用户信息, 用户ID数量: {}", userIds.size());
        
        List<SysUser> sysUsers = userMapper.selectListByCondition(SYS_USER.ID.in(userIds));
        
        if (CollUtil.isEmpty(sysUsers)) {
            log.warn("未查询到用户信息");
            return;
        }
        
        log.debug("查询到用户数量: {}", sysUsers.size());
        setUserInfo(voList, sysUsers);
    }

    /**
     * 递归set用户信息
     */
    private void setUserInfo(List<PostCommentVo> voList, List<SysUser> sysUsers) {
        if (CollUtil.isNotEmpty(voList)) {
            voList.forEach(item -> {
                if (item.getAuthorId() == null) {
                    log.warn("评论的作者ID为空: {}", item.getId());
                    return;
                }
                
                SysUser sysUser = sysUsers.stream()
                    .filter(e -> e.getId() != null && e.getId().equals(item.getAuthorId()))
                    .findFirst()
                    .orElse(null);
                    
                if (sysUser != null) {
                item.setAuthorName(sysUser.getNickName());
                item.setAuthorAvatar(sysUser.getAvatar());
                } else {
                    log.warn("未找到用户信息: authorId={}", item.getAuthorId());
                    // 设置默认值，避免前端显示问题
                    item.setAuthorName("未知用户");
                    item.setAuthorAvatar("");
                }
                
                if (item.getChildren() != null) {
                setUserInfo(item.getChildren(), sysUsers);
                }
            });
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean removeRecursionById(Serializable id) {
        log.info("递归删除评论: id={}", id);
        
        if (id == null) {
            log.error("删除评论失败：评论ID为空");
            return false;
        }
        
        try {
        removeById(id);
        removeChildren(id);
        return true;
        } catch (Exception e) {
            log.error("删除评论失败: id={}", id, e);
            throw e;
        }
    }

    private void removeChildren(Serializable parentId) {
        if (parentId == null) {
            return;
        }
        
        List<Long> childrenIds = QueryChain.of(commentMapper)
                .select(OJ_POST_COMMENT.ID)
                .where(OJ_POST_COMMENT.PARENT_ID.eq(parentId))
                .listAs(Long.class);
                
        log.debug("查询到子评论数量: {}, parentId={}", childrenIds.size(), parentId);
        
        for (Long childrenId : childrenIds) {
            removeById(childrenId);
            removeChildren(childrenId);
        }
    }

    @Override
    public Long getNum(String postId) {
        if (StringUtil.isBlank(postId)) {
            log.error("获取评论数量失败：帖子ID为空");
            return 0L;
        }
        
        log.info("获取帖子评论数量: postId={}", postId);
        
        try {
            Long postIdLong = Long.parseLong(postId);
            
        long count = postMapper
                    .selectCountByCondition(OJ_POST.ID.eq(postIdLong));
        if (count == 0) {
                log.error("获取评论数量失败：帖子不存在, postId={}", postId);
            throw new BusinessException("帖子不存在");
        }
            
            Long commentCount = commentMapper.selectCountByCondition(OJ_POST_COMMENT.POST_ID.eq(postIdLong));
            log.info("帖子评论数量: {}, postId={}", commentCount, postId);
            
            return commentCount;
        } catch (NumberFormatException e) {
            log.error("获取评论数量失败：帖子ID格式错误, postId={}", postId, e);
            return 0L;
        }
    }
}
